/*!
    \copyright  Copyright (c) 2025 Qualcomm Technologies International, Ltd.
                All Rights Reserved.
                Qualcomm Technologies International, Ltd. Confidential and Proprietary.
    \version    
    \file       accessory_device_service_handover.c
    \ingroup    accessory_device_service
    \brief      Accessory Device Service handover related interfaces
*/

#if defined(ENABLE_LE_HANDOVER) && defined(INCLUDE_ACCESSORY_DEVICE_SERVICE)

#include <panic.h>
#include <stdlib.h>
#include <sink.h>
#include <stream.h>
#include <source.h>
#include "marshal.h"
#include "handover_if.h"
#include "logging.h"

#include "connection_manager.h"

#include "accessory_device_service_private.h"
#include "accessory_device_service_marshal_desc.h"

/*! Use this flag to clean unmarshalled data, if any, during handover abort phase */
static bool unmarshalled = FALSE;

/*! \brief Handover veto check for Accessories.

    \return bool Veto the handover if accessory is in pairing state else return false
*/
static bool accessoryDeviceService_VetoLink(const typed_bdaddr *tp_bd_addr)
{
    bool veto = FALSE;
    accessory_device_t *accessory = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_bd_addr);

    /* veto if accessory device service state for the LE link is not in a stable state */
    if (accessory != NULL && accessory->state == ACCESSORY_DEVICE_SERVICE_STATE_PAIRING)
    {
        veto = TRUE;
        DEBUG_LOG_INFO("accessoryDeviceService_VetoLink, Unstable accessory state : ACCESSORY_DEVICE_SERVICE_STATE_PAIRING");
    }

    return veto;
}

static bool accessoryDeviceService_Veto(void)
{
    bool veto = FALSE;
    accessory_device_t *device_entry = NULL;

    ARRAY_FOREACH(device_entry, accessoryDeviceService_GetData()->accessory_devices)
    {
        /* Veto the handover if an accessory information had added but user yet to connect and pair to it */
        if (device_entry->state == ACCESSORY_DEVICE_SERVICE_STATE_PAIRING)
        {
            DEBUG_LOG_INFO("accessoryDeviceService_Veto as unstable accessory state");

            veto = TRUE;
            break;
        }
    }

    return veto;
}

static bool accessoryDeviceService_Marshal(const tp_bdaddr *tp_bd_addr,
                                     uint8 *buf,
                                     uint16 length,
                                     uint16 *written)
{
    accessory_device_t *accessory = AccessoryDeviceService_GetDeviceEntryForTpAddr(tp_bd_addr);
    accessory_device_service_marshal_data_t obj;

    if (accessory != NULL)
    {
        obj.state = accessory->state;
        obj.type = accessory->type;

        marshaller_t marshaller = MarshalInit(mtdesc_accessory_device_service, ACCESSORY_DEVICE_SERVICE_MARSHAL_OBJ_TYPE_COUNT);
        MarshalSetBuffer(marshaller, (void*)buf, length);
        bool marshalled = Marshal(marshaller, &obj, MARSHAL_TYPE(accessory_device_service_marshal_data_t));
        *written = marshalled ? MarshalProduced(marshaller) : 0;
        MarshalDestroy(marshaller, FALSE);
        return marshalled;
    }

    *written = 0;
    return TRUE;
}

static bool accessoryDeviceService_Unmarshal(const tp_bdaddr *tp_bd_addr,
                                       const uint8 *buf,
                                       uint16 length,
                                       uint16 *consumed)
{
    unmarshaller_t unmarshaller = UnmarshalInit(mtdesc_accessory_device_service, ACCESSORY_DEVICE_SERVICE_MARSHAL_OBJ_TYPE_COUNT);
    UnmarshalSetBuffer(unmarshaller, (void *)buf, length);

    accessory_device_service_marshal_data_t *data = NULL;
    marshal_type_t unmarshalled_type;

    if (Unmarshal(unmarshaller, (void **)&data, &unmarshalled_type))
    {
        PanicFalse(unmarshalled_type == MARSHAL_TYPE(accessory_device_service_marshal_data_t));
        PanicNull(data);

        AccessoryDeviceService_CreateDeviceEntry(tp_bd_addr, data->type, data->state);
        *consumed = UnmarshalConsumed(unmarshaller);
        unmarshalled = TRUE;
        UnmarshalDestroy(unmarshaller, TRUE);
        return TRUE;
    }
    else
    {
        *consumed = 0;
        UnmarshalDestroy(unmarshaller, TRUE);
        return FALSE;
    }
}

/*! \brief Handle commit for Accessory Device service */
static void accessoryDeviceService_HandoverCommit(const tp_bdaddr *tp_bd_addr, bool is_primary)
{
    DEBUG_LOG_FN_ENTRY("accessoryDeviceService_Commit");

    if (is_primary)
    {
        /* TODO : Populate state machine for the active device connections as per connection manager records 
           and register the device with DeviceProperty */

    }
    else
    {
        AccessoryDeviceService_Reset();
    }
}

/*! \brief Handle handover complete for Accessory device service */
static void accessoryDeviceService_HandoverComplete(const bool is_primary)
{
    UNUSED(is_primary);
    /* mark complete of unmarshalled data */
    unmarshalled = FALSE;
}

/*! \brief On abort, reset the Accessory Device service task data in the secondary */
static void accessoryDeviceService_HandoverAbort(void)
{
    DEBUG_LOG("accessoryDeviceService_HandoverAbort");

    if (unmarshalled)
    {
        AccessoryDeviceService_Reset();
        unmarshalled = FALSE;
    }
}

/*! \brief On abort, Accessory device service handover interfaces */
const handover_interface accessory_device_service_handover_if =
        MAKE_HANDOVER_IF_VPL(&accessoryDeviceService_Veto,
                             &accessoryDeviceService_VetoLink,
                             &accessoryDeviceService_Marshal,
                             &accessoryDeviceService_Unmarshal,
                             &accessoryDeviceService_HandoverCommit,
                             &accessoryDeviceService_HandoverComplete,
                             &accessoryDeviceService_HandoverAbort);

#endif /* defined(ENABLE_LE_HANDOVER) && defined(INCLUDE_ACCESSORY_DEVICE_SERVICE) */
